# 浏览器渲染原理
- HTML代码转化为DOM;
- CSS代码转化为CSSOM(CSS Object Model);
- 两种树结合,生成一课渲染树Render Tree(包含每个节点的视觉信息,可以想象成是个三维的树);
- 生成布局(layout),即将渲染树的所有节点进行平面排布(flow)(可以想象成是三维树排布成平面树,若再次触发这种排布,就称为重排或回流);
- 将布局绘制(print)在屏幕上(若再次触发这种绘制,就称为重绘) 注:
- 1-3很快,耗时的是4和5,4和5合起来称为“渲染”
- 重排一定重绘,重绘不一定重排
- dom操作很消耗性能的原因:a.涉及JS引擎和渲染引擎跨线程的通信; b.会频繁触发重排和重绘。
重排和重绘:
- 重排:对DOM的修改导致了几何属性的变化(比如:长宽、位置、显隐等),会触发浏览器重新计算、重新排布dom,然后再绘制出来。
长宽、位置position、显隐display、窗口大小改变触发resize事件、获取style对象上的属性(offsetWidth、offsetHeight、offsetTop等)!!—— 查询style属性会强制发生重排
- 重绘:对DOm的修改不会导致几何属性变化(比如:背景色、文字颜色等),无需计算,直接绘制即可。
color、background、visibility、border-radius、border-color
如何减少重排和重绘?
- 避免使用table实现布局,因为细微的改动都可能导致整个页面重排;
- 使用visibility:hidden;替换display:none;这样只会重绘不会重排;
- 使用transform:translateX替换top等,因为transform是绘制层的属性,不会触发重排;
- 避免频繁查询 style对象上的样式属性,例如 document.getElementById('#app').style.offsetTop等,因为查询style属性会强制发生重排;
- 设置图层z-index。
# 常见浏览器内核
浏览器内核分为两部分:渲染引擎和JS引擎。一般讲浏览器内核都是指渲染引擎。
浏览器 | 渲染引擎 | JS引擎 |
---|---|---|
IE -> Edge | Trident -> EdgeHTML | JScript |
FireFox | Gecko | JaegerMonkey |
Safari | Webkit | Nitro |
Chrome | Webkit -> Blink | V8 |
Opera | Presto -> Blink | Carakan |
Blink 是 Webkit 的分支,所以本质上 Safari、Chrome、Opera 都是 Webkit
js
加载会阻塞DOM构建吗?
- 不仅会阻塞DOM构建,还有导致CSSOM也阻塞DOM的构建。
css
加载会阻塞dom
解析吗?
正常情况下,css的加载和解析,与dom的加载和解析同步进行,此时不会阻塞dom的解析,但是有一种情况:浏览器尚未完成CSSOM的下载和构建,而我们却想在此时运行脚本,那么浏览器将延迟脚本执行和DOM构建,直至其完成CSSOM的下载和构建。也就是说,在这种情况下,浏览器会先下载和构建CSSOM,然后再执行JavaScript,最后在继续构建DOM。
减少白屏,应提高css加载速度:
- 使用
CDN
; - 进行压缩(
webpack
、gulp
等进行打包,或开启gzip
压缩); - 合理使用缓存(设置cache-control、expires、e-tag);
- 减少请求数(合并资源)。
浏览器如何解析css选择器?
浏览器会『从右往左』解析CSS选择器。
从dom树
和css树
渲染生成渲染树,实际上是将css
样式附着到对应的dom
节点上,而每附着一个样式都要对dom树
进行遍历。
以这段代码为例:
.mod-nav h3 span {font-size: 16px;}
对应的dom树
结构如下:
若从左向右匹配,即从根节点开始沿每个节点分支进行遍历,结果是每个分支都要被遍历一次; 但是从右向左匹配,可以直接剔除很多分支,可以大大提高遍历效率。
DOMContentLoaded 与 load 区别?
load
:等待页面所有资源加载完成才会触发,包括css、js、图片等;DOMContentLoaded
:等待dom资源加载、解析完成就会触发;DOMContentLoaded
总是早于load
触发。
async
与defer
的区别?
- 有
async
,加载和渲染后边的html
,将与js
的加载并行进行,且先加载完成的async
优先执行,即执行顺序与加载顺序无关,不确定在DOMContentLoaded
之前或之后执行,但一定在load
之前执行。适用于不操作dom
的js
文件的加载。 - 有
defer
,加载和渲染后边的html
,将与js
的加载并行进行,但js
的执行要在html
解析结束且DOMContentLoaded
触发之前,而且执行顺序与加载顺序一致。适用于彼此有依赖关系的js
文件的加载。
综上所述,我们得出这样的结论:
- 浏览器工作流程:构建DOM -> 构建CSSOM -> 构建渲染树 -> 布局 -> 绘制。
- CSSOM会阻塞渲染,只有当CSSOM构建完毕后才会进入下一个阶段构建渲染树。
- 通常情况下DOM和CSSOM是并行构建的,但是当浏览器遇到一个不带defer或async属性的script标签时,DOM构建将暂停,如果此时又恰巧浏览器尚未完成CSSOM的下载和构建,由于JavaScript可以修改CSSOM,所以需要等CSSOM构建完毕后再执行JS,最后才继续DOM构建。
参考: https://juejin.im/post/5e143104e51d45414a4715f7
https://fed.taobao.org/blog/taofed/do71ct/performance-composite/?spm=taofed.blogs.blog-list.10.67bd5ac8fHy0LS
https://zhuanlan.zhihu.com/p/47407398
https://juejin.im/post/5a6547d0f265da3e283a1df7